package org.dromara.llm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.llm.domain.FileLang;
import org.dromara.llm.domain.FilesStatus;
import org.dromara.llm.domain.UploadedFiles;
import org.dromara.llm.mapper.FileLangMapper;
import org.dromara.llm.mapper.UploadedFilesMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

@Component
@Slf4j
@RequiredArgsConstructor
public class ScriptExecutor {
    private final UploadedFilesMapper fileRepository;
    private final FileLangMapper langFileMapper;
    /**
     * 上传目录
     */
    @Value("${app.upload-dir}")
    private String uploadDir;

    /**
     * 脚本文件
     */
    @Value("${app.process-script}")
    private String processScript;

    /**
     * 执行文件处理(入口)
     *
     * 本方法根据文件实体的状态和语言信息，调用外部脚本处理文件，并更新文件的处理状态和结果
     * 如果文件已经处理完成或找不到对应语言文件，则不会执行处理操作
     *
     * @param fileEntity 文件实体，包含文件信息和处理状态
     */
    @Async
    public void executeFile(UploadedFiles fileEntity) {
        try {
            // 检查文件是否已经处理完成
            if (Objects.equals(fileEntity.getProcessStatus(), FilesStatus.COMPLETED.getStatusCode())) {
                log.info("文件已处理完成");
                return;
            }
            // 语言种类获取文件名称，如：en,zh
            FileLang queryCondition = new FileLang();
            queryCondition.setLang(fileEntity.getLang()); // 假设根据 lang 字段查询
            FileLang resultLangFile = langFileMapper.selectOne(new QueryWrapper<>(queryCondition));

            // 检查是否存在对应语言的文件
            if (Objects.isNull(resultLangFile)) {
                log.info("未找到对应的语言文件");
                return;
            }

            // 调用外部脚本处理文件
            String result = executeScript(resultLangFile.getFilePath() + "\\" +resultLangFile.getLangFileName(),
                uploadDir + "\\" +fileEntity.getId()+".json",
                fileEntity.getFilePath());

            // 更新文件的处理状态和结果
            fileEntity.setProcessStatus(FilesStatus.COMPLETED.getStatusCode());
            fileEntity.setProcessResult(result);
            fileRepository.updateById(fileEntity);
        } catch (Exception e) {
            // 处理异常情况，更新文件处理状态为失败，并记录异常信息
            fileEntity.setProcessStatus(FilesStatus.FAILED.getStatusCode());
            fileEntity.setProcessResult(e.getMessage());
            fileRepository.updateById(fileEntity);
            log.info("文件处理失败:{}", e.getMessage());
        }
    }

    /**
     * 执行特定脚本并返回输出结果
     * 该方法根据提供的语言、JSON文件名和语音文件名构建命令，并通过ProcessBuilder执行
     *
     * @param language 脚本语言
     * @param jsonFileName 输出JSON文件名
     * @param voiceFileName 语音文件名
     * @return 脚本执行的输出结果
     * @throws IOException 如果执行过程中发生I/O错误
     * @throws InterruptedException 如果等待过程被中断
     */
    public String executeScript(String language,String jsonFileName, String voiceFileName) throws IOException, InterruptedException {
        // 参数校验
        if (language == null || jsonFileName == null || voiceFileName == null) {
            log.info("Parameters cannot be null");
            throw new IllegalArgumentException("Parameters cannot be null");
        }

        // 构建命令
        List<String> commandList = Arrays.asList(processScript, language, jsonFileName, voiceFileName);

        // 创建ProcessBuilder实例并配置
        ProcessBuilder processBuilder = new ProcessBuilder(commandList);
        processBuilder.redirectErrorStream(true); // 合并错误流

        // 启动进程
        Process process = processBuilder.start();

        // 读取并记录进程输出
        StringBuilder output = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                output.append(line).append("\n");
            }
        }

        // 等待进程结束并获取退出码
        int exitCode = process.waitFor();

        // 根据退出码处理执行结果
        if (exitCode != 0) {
            log.error("Script execution failed with exit code: {}, Command: {}, Output: {}",
                    exitCode, commandList, output);
        } else {
            // 若你确实需要从文件中读取最终结果，请注释掉上面一行，并启用以下逻辑：
            output.delete(0, output.length());
            List<String> lines = Files.readAllLines(Paths.get(jsonFileName));
            for (String line : lines) {
                output.append(line).append("\n");
            }
        }
        return output.toString();
    }




}
